package com.mioto.ld.security.filter;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.mioto.ld.module.personal.model.UserInfoVO;
import com.mioto.ld.module.personal.model.UserStatus;
import com.mioto.ld.module.personal.model.UserType;
import com.mioto.ld.module.personal.service.IUserService;
import com.mioto.ld.security.AuthParamException;
import com.mioto.ld.security.ForbidLoginException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

/**
 * @author mioto-qinxj
 * @date 2024/4/11
 * @desc 登录认证
 */
@Component
public class BasicAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    @Resource
    private IUserService userService;

    private final String[] clientTypes = {"web","app"};

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
        String username = httpServletRequest.getParameter("username");
        String password = httpServletRequest.getParameter("password");
        String clientType = httpServletRequest.getParameter("clientType");
        if (StrUtil.isEmpty(clientType) || !ArrayUtil.contains(clientTypes,clientType)){
            throw new AuthParamException("clientType传参错误");
        }
        UserInfoVO user = userService.findDetailByUsername(username);
        if (ObjectUtil.isNotNull(user)) {
            if (ObjectUtil.equal("web", clientType) && ObjectUtil.equal(user.getUserType(), UserType.USER_TYPE_APP)){
                throw new ForbidLoginException("app用户禁止登录");
            }
            if (!new BCryptPasswordEncoder().matches(password, user.getPassword())) {
                throw new BadCredentialsException("密码错误");
            } else if (user.getStatus().equals(UserStatus.USER_STATUS_DISABLE)) {
                throw new DisabledException("用户被禁用");
            }

            Set<SimpleGrantedAuthority> grantedAuthorities = new HashSet<>();
            grantedAuthorities.add(new SimpleGrantedAuthority(StrUtil.toString(user.getRoleId())));
            return new UsernamePasswordAuthenticationToken(user, new Object(), grantedAuthorities);
        }
        throw new UsernameNotFoundException("用户不存在");
    }

    @Autowired
    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    public BasicAuthenticationProcessingFilter() {
        super(new AntPathRequestMatcher("/login", "POST"));
    }

    @Override
    @Autowired
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
        super.setAuthenticationSuccessHandler(successHandler);
    }

    @Override
    @Autowired
    public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
        super.setAuthenticationFailureHandler(failureHandler);
    }
}
